package com.example.artemis.events;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 事件总线
 * 提供全局的事件发布和订阅管理
 * 使用单例模式确保全局唯一性
 */
public class EventBus {

    private static final Logger logger = LoggerFactory.getLogger(EventBus.class);

    // 单例实例
    private static volatile EventBus instance;

    // 全局事件发布器
    private final EventPublisher globalPublisher;

    // 命名发布器映射（用于不同模块独立使用）
    private final ConcurrentMap<String, EventPublisher> namedPublishers = new ConcurrentHashMap<>();

    private EventBus() {
        this.globalPublisher = new EventPublisher();
        logger.info("事件总线初始化完成");
    }

    /**
     * 获取事件总线单例实例
     *
     * @return 事件总线实例
     */
    public static EventBus getInstance() {
        if (instance == null) {
            synchronized (EventBus.class) {
                if (instance == null) {
                    instance = new EventBus();
                }
            }
        }
        return instance;
    }

    /**
     * 获取全局事件发布器
     *
     * @return 全局事件发布器
     */
    public EventPublisher getGlobalPublisher() {
        return globalPublisher;
    }

    /**
     * 获取命名事件发布器
     * 如果不存在则创建新的发布器
     *
     * @param name 发布器名称
     * @return 命名事件发布器
     */
    public EventPublisher getPublisher(String name) {
        return namedPublishers.computeIfAbsent(name, k -> {
            logger.debug("创建命名事件发布器: {}", k);
            return new EventPublisher();
        });
    }

    /**
     * 移除命名事件发布器
     *
     * @param name 发布器名称
     * @return 如果移除成功返回true
     */
    public boolean removePublisher(String name) {
        EventPublisher publisher = namedPublishers.remove(name);
        if (publisher != null) {
            publisher.shutdown();
            logger.debug("移除命名事件发布器: {}", name);
            return true;
        }
        return false;
    }

    /**
     * 向全局发布器注册监听器
     *
     * @param listener 监听器
     * @param <T>      事件类型
     */
    public <T extends MessageEvent> void registerGlobalListener(EventListener<T> listener) {
        globalPublisher.registerListener(listener);
    }

    /**
     * 从全局发布器注销监听器
     *
     * @param listener 监听器
     */
    public void unregisterGlobalListener(EventListener<? extends MessageEvent> listener) {
        globalPublisher.unregisterListener(listener);
    }

    /**
     * 向全局发布器发布事件
     *
     * @param event 事件
     * @param <T>   事件类型
     */
    public <T extends MessageEvent> void publish(T event) {
        globalPublisher.publishEvent(event);
    }

    /**
     * 向全局发布器异步发布事件
     *
     * @param event 事件
     * @param <T>   事件类型
     */
    public <T extends MessageEvent> void publishAsync(T event) {
        globalPublisher.publishEventAsync(event);
    }

    /**
     * 获取统计信息
     *
     * @return 统计信息字符串
     */
    public String getStatistics() {
        StringBuilder stats = new StringBuilder();
        stats.append("事件总线统计信息:\n");
        stats.append(String.format("  全局发布器监听器数: %d\n", globalPublisher.getListenerCount()));
        stats.append(String.format("  命名发布器数量: %d\n", namedPublishers.size()));

        namedPublishers.forEach((name, publisher) ->
                stats.append(String.format("    %s: %d 个监听器\n", name, publisher.getListenerCount())));

        return stats.toString();
    }

    /**
     * 关闭事件总线，释放所有资源
     */
    public void shutdown() {
        logger.info("关闭事件总线...");

        // 关闭全局发布器
        globalPublisher.shutdown();

        // 关闭所有命名发布器
        namedPublishers.values().forEach(EventPublisher::shutdown);
        namedPublishers.clear();

        logger.info("事件总线已关闭");
    }

    /**
     * 强制关闭事件总线
     */
    public void shutdownNow() {
        logger.warn("强制关闭事件总线...");

        globalPublisher.shutdownNow();
        namedPublishers.values().forEach(EventPublisher::shutdownNow);
        namedPublishers.clear();

        logger.info("事件总线已强制关闭");
    }
}